﻿<!DOCTYPE HTML>
<html lang="zh">
<head>
<title>CallbackCreate - 语法 &amp; 使用 | AutoHotkey v2</title>
<meta name="description" content="The CallbackCreate function creates a machine-code address that when called, redirects the call to a function in the script." />
<meta name="ahk:equiv-v1" content="commands/RegisterCallback.htm" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
<script type="text/javascript">$(function(){0<=window.navigator.userAgent.toLowerCase().indexOf("ucbrowser")&&CaoNiMaDeUc()})</script>
</head>
<body>

<h1>CallbackCreate</h1>

<p>创建机器码地址, 当它被调用时会重定向到脚本中的<a href="../Functions.htm">函数</a>.</p>

<pre class="Syntax">Address := <span class="func">CallbackCreate</span>(Function <span class="optional">, Options := "", ParamCount := Function.MinParams</span>)</pre>
<h2 id="Parameters">参数</h2>
<dl>

  <dt>Function</dt>
  <dd>
    <p>类型: <a href="../Concepts.htm#strings">字符串</a>或<a href="../Concepts.htm#objects">对象</a></p>
    <p>函数名或<a href="../objects/Functor.htm">函数对象</a>. 每当调用 <em>Address</em> 时会自动调用此函数. 此函数同时会接收到传递给 <em>Address</em> 的参数.</p>
    <p><a href="../Functions.htm#closures">闭包</a>或<a href="../objects/Functor.htm#BoundFunc">绑定函数</a>可以用来区分多个回调函数调用相同的脚本函数.</p>
    <p>回调函数保留对函数对象的引用, 并在脚本调用 <a href="#CallbackFree">CallbackFree</a> 时释放它.</p>
  </dd>

  <dt>Options</dt>
  <dd>
    <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
    <p>指定零个或多个下列单词或字符串. 在选项间使用空格分隔(例如 <code>"C Fast"</code>).</p>
    <p id="Fast"><strong>Fast</strong> 或 <strong>F</strong>: 避免每次调用 <em>Function</em> 时都启动新的<a href="../misc/Threads.htm">线程</a>. 尽管这样执行的更好, it must be avoided whenever the thread from which <em>Address</em> is called varies (e.g. when the callback is triggered by an incoming message). This is because <em>FunctionName</em> will be able to change global settings such as <a href="../misc/ErrorLevel.htm">ErrorLevel</a>, <a href="../Variables.htm#LastError">A_LastError</a>, and the <a href="../misc/WinTitle.htm#LastFoundWindow">last-found window</a> for whichever thread happens to be running at the time it is called. For more information, 请参阅 <a href="#Threads">Remarks</a>.</p>
    <p><strong>CDecl</strong> or <strong>C</strong>: Makes <em>Address</em> conform to the &quot;C&quot; calling convention. This is typically omitted because the standard calling convention is much more common for callbacks. This option is ignored by 64-bit versions of AutoHotkey, which use the x64 calling convention.</p>
    <p><strong>&amp;</strong>: Causes the address of the parameter list (a single integer) to be passed to <em>Function</em> instead of the individual parameters. Parameter values can be retrieved by using <a href="NumGet.htm">NumGet</a>. When using the standard 32-bit calling convention, <em>ParamCount</em> must specify the size of the parameter list in DWORDs (the number of bytes divided by 4).</p>
  </dd>

  <dt>ParamCount</dt>
  <dd>
    <p>类型: <a href="../Concepts.htm#numbers">整数</a></p>
    <p>The number of parameters that <em>Address</em>'s caller will pass to it. If omitted, it defaults to <code><i>Function</i>.<a href="../objects/Func.htm#MinParams">MinParams</a></code>, which is usually the number of mandatory parameters in the <a href="../Functions.htm#define">definition</a> of <em>Function</em>. In either case, ensure that the caller passes exactly this number of parameters.</p>
  </dd>

</dl>

<h2 id="Return_Value">返回值</h2>
<p>类型: <a href="../Concepts.htm#numbers">整数</a></p>
<p>CallbackCreate returns a machine-code address. This address is typically passed to an external function via <a href="DllCall.htm">DllCall</a> or placed in a struct using <a href="NumPut.htm">NumPut</a>, but can also be called directly by DllCall. Passing the address to <a href="#CallbackFree">CallbackFree</a> will delete the callback.</p>

<h2 id="failure">Failure</h2>
<p>This function fails and throws an exception under any of the following conditions:</p>
<ul>
  <li><em>Function</em> is not an object or a valid function name.</li>
  <li><em>Function</em> has a <code>MinParams</code> property which exceeds the number of parameters that the callback will supply.</li>
  <li><em>ParamCount</em> is negative.</li>
  <li><em>ParamCount</em> is omitted and: 1) <em>Function</em> has no <code>MinParams</code> property; or 2) the <code>&amp;</code> option is used with the standard 32-bit calling convention.</li>
</ul>

<h2>The Callback Function's 参数</h2>
<p>A <a href="../Functions.htm">function</a> assigned to a callback address may accept up to 31 parameters. <a href="../Functions.htm#optional">Optional parameters</a> are permitted, which is useful when the function is called by more than one caller.</p>
<p>Interpreting the parameters correctly requires some understanding of how the x86 calling conventions work. Since AutoHotkey does not have typed parameters, the callback's parameter list is assumed to consist of integers, and some reinterpretation may be required.</p>

<p><strong>AutoHotkey 32-bit:</strong> All incoming parameters are unsigned 32-bit integers. Smaller types are padded out to 32 bits, while larger types are split into a series of 32-bit parameters.</p>
<p>If an incoming parameter is intended to be a signed integer, any negative numbers can be revealed by following either of the following examples:</p>
<pre><em>; Method #1</em>
if (wParam &gt; 0x7FFFFFFF)
    wParam := -(~wParam) - 1

<em>; Method #2: Relies on the fact that AutoHotkey natively uses signed 64-bit integers.</em>
wParam := wParam &lt;&lt; 32 &gt;&gt; 32</pre>

<p><strong>AutoHotkey 64-bit:</strong> All incoming parameters are signed 64-bit integers. AutoHotkey does not natively support unsigned 64-bit integers. Smaller types are padded out to 64 bits, while larger types are always passed by address.</p>

<p><strong>AutoHotkey 32-bit/64-bit:</strong> If an incoming parameter is intended to be 8-bit or 16-bit (or 32-bit on x64), the upper bits of the value might contain "garbage" which can be filtered out by using bitwise-and, as in the following examples:</p>
<pre>Callback(UCharParam, UShortParam, UIntParam) {
    UCharParam &amp;= 0xFF
    UShortParam &amp;= 0xFFFF
    UIntParam &amp;= 0xFFFFFFFF
    <em>;...</em>
}</pre>
<p>If an incoming parameter is intended by its caller to be a string, what it actually receives is the address of the string. To retrieve the string itself, use <a href="StrGet.htm">StrGet</a>:</p>
<pre>MyString := StrGet(MyParameter)</pre>
<p>If an incoming parameter is the address of a structure, the individual members may be extracted by following the steps at <a href="DllCall.htm#struct">DllCall structures</a>.</p>

<p id="Indirect"><strong>Receiving parameters by address:</strong> If the <code>&amp;</code> option is used, the function receives the <i>address</i> of the first callback parameter. 例如:</p>
<pre>
callback := CallbackCreate("TheFunc", "F&amp;", 3)  <em>; Parameter list size must be specified for 32-bit.</em>
DllCall(callback, &quot;float&quot;, 10.5, &quot;int64&quot;, 42)
TheFunc(params) {
    MsgBox <a href="NumGet.htm">NumGet</a>(params+0, "float") ", " NumGet(params+A_PtrSize, "int64")
}</pre>
<p>Most callbacks in 32-bit programs use the <em>stdcall</em> calling convention, which requires a fixed number of parameters. In those cases, <em>ParamCount</em> must be set to the size of the parameter list, where Int64 and Double count as two 32-bit parameters. With <em>Cdecl</em> or the 64-bit calling convention, <em>ParamCount</em> has no effect.</p>

<h2>What the Function Should <em>Return</em></h2>
<p>If the function uses <a href="Return.htm">Return</a> without any parameters, or it specifies a blank value such as &quot;&quot; (or it never uses Return at all), 0 is returned to the caller of the callback. Otherwise, the function should return an integer, which is then returned to the caller. AutoHotkey 32-bit truncates return values to 32-bit, while AutoHotkey 64-bit supports 64-bit return values. Returning structs larger than this (by value) is not supported.</p>

<h2 id="Threads">Fast vs. Slow</h2>
<p>The default/slow mode causes the function to start off fresh with the default values for settings such as <a href="SendMode.htm">SendMode</a> and <a href="DetectHiddenWindows.htm">DetectHiddenWindows</a>. These defaults can be changed in the <a href="../Scripts.htm#auto">auto-execute section</a>.</p>
<p>By contrast, the <a href="#Fast">fast mode</a> inherits global settings from whichever <a href="../misc/Threads.htm">thread</a> happens to be running at the time the function is called. Furthermore, any changes the function makes to global settings (including <a href="../misc/ErrorLevel.htm">ErrorLevel</a> and the <a href="../misc/WinTitle.htm#LastFoundWindow">last-found window</a>) will go into effect for the <a href="../misc/Threads.htm">current thread</a>. Consequently, the fast mode should be used only when it is known exactly which thread(s) the function will be called from.</p>
<p>To avoid being interrupted by itself (or any other thread), a callback may use <a href="Critical.htm">Critical</a> as its first line. However, this is not completely effective when the function is called indirectly via the arrival of a message less than 0x312 (increasing Critical's <a href="Critical.htm#Interval">interval</a> may help). Furthermore, <a href="Critical.htm">Critical</a> does not prevent the function from doing something that might indirectly result in a call to itself, such as calling <a href="SendMessage.htm">SendMessage</a> or <a href="DllCall.htm">DllCall</a>.</p>

<h2 id="CallbackFree">Memory</h2>
<p>Each use of CallbackCreate allocates a small amount of memory (32 bytes plus system overhead). Since the OS frees this memory automatically when the script exits, any script that allocates a small, <em>fixed</em> number of callbacks does not have to explicitly free the memory. By contrast, a script that calls CallbackCreate an indefinite/unlimited number of times should explicitly call the following on any unused callbacks:</p>
<pre>CallbackFree(Address)</pre>
<p>This also releases the callback's reference to the script's function object.</p>

<h2 id="Related">相关</h2>
<p><a href="DllCall.htm">DllCall</a>, <a href="OnMessage.htm">OnMessage</a>, <a href="OnExit.htm">OnExit</a>, <a href="OnClipboardChange.htm">OnClipboardChange</a>, <a href="Sort.htm#callback">Sort's callback</a>, <a href="Critical.htm">Critical</a>, <a href="PostMessage.htm">PostMessage</a>, <a href="SendMessage.htm">SendMessage</a>, <a href="../Functions.htm">Functions</a>, <a href="../misc/SendMessageList.htm">List of Windows Messages</a>, <a href="../misc/Threads.htm">Threads</a></p>

<h2 id="Examples">示例</h2>
<div class="ex" id="ExWinList">
<p><a href="#ExWinList">#1</a>: 下面是个可运行脚本, 它显示了所有顶层窗口的摘要.</p>
<pre><em>; 考虑到性能和内存的保持, 只为指定的回调调用一次 CallbackCreate:</em>
if not EnumAddress  <em>; 由于只能从这个线程调用, 所以可以使用快速模式:</em>
    EnumAddress := <strong>CallbackCreate</strong>(&quot;EnumWindowsProc&quot;, &quot;Fast&quot;)

DetectHiddenWindows True  <em>; 由于是快速模式, 所以此设置也会在回调中生效.</em>

<em>; 把控制传给 EnumWindows(), 它会重复调用回调:</em>
DllCall(&quot;EnumWindows&quot;, &quot;Ptr&quot;, EnumAddress, &quot;Ptr&quot;, 0)
MsgBox Output  <em>; 显示由回调收集的信息.</em>
    
EnumWindowsProc(hwnd, lParam)
{
    global Output
    title := WinGetTitle("ahk_id " hwnd)
    class := WinGetClass("ahk_id " hwnd)
    if title
        Output .= &quot;HWND: &quot; . hwnd . &quot;`tTitle: &quot; . title . &quot;`tClass: &quot; . class . &quot;`n&quot;
    return true  <em>; 告知 EnumWindows() 继续执行, 一直到枚举完所有的窗口.</em>
}</pre>
</div>

<div class="ex" id="ExSubclassGUI">
<p><a href="#ExSubclassGUI">#2</a>: 下面是个可运行脚本, 它演示了如何在脚本中通过把 GUI 窗口的 WindowProc 重定向到新的 WindowProc 来子类化窗口. 此时, 文本控件的背景颜色被改变为自定义颜色.</p>
<pre>TextBackgroundColor := 0xFFBBBB  <em>; BGR 格式的自定义颜色.</em>
TextBackgroundBrush := DllCall(&quot;CreateSolidBrush&quot;, &quot;UInt&quot;, TextBackgroundColor)

Gui := GuiCreate()
Text := Gui.Add("Text",, "Here is some text that is given`na custom background color.")

<em>; 64 位脚本必须调用 SetWindowLongPtr 代替 SetWindowLong:</em>
SetWindowLong := A_PtrSize=8 ? "SetWindowLongPtr" : "SetWindowLong"

WindowProcNew := <strong>CallbackCreate</strong>("WindowProc")  <em>; 避免子类化中使用快速模式.</em>
WindowProcOld := DllCall(SetWindowLong, &quot;Ptr&quot;, Gui.Hwnd, &quot;Int&quot;, -4  <em>; -4 为 GWL_WNDPROC</em>
    , &quot;Ptr&quot;, WindowProcNew, &quot;Ptr&quot;) <em>; 返回值必须设置为 &quot;Ptr&quot; 或 &quot;UPtr&quot; 而不是 &quot;Int&quot;.</em>

Gui.Show

WindowProc(hwnd, uMsg, wParam, lParam)
{
    Critical
    global Text, TextBackgroundColor, TextBackgroundBrush, WindowProcOld
    if (uMsg = 0x138 &amp;&amp; lParam = Text.Hwnd)  <em>; 0x138 为 WM_CTLCOLORSTATIC.</em>
    {
        DllCall(&quot;SetBkColor&quot;, &quot;Ptr&quot;, wParam, &quot;UInt&quot;, TextBackgroundColor)
        return TextBackgroundBrush  <em>; 返回 HBRUSH 来通知操作系统我们改变了 HDC.</em>
    }
    <em>; 否则(因为上面没有返回), 将所有的未处理事件传递给原来的 WindowProc.</em>
    return DllCall(&quot;CallWindowProc&quot;, &quot;Ptr&quot;, WindowProcOld, &quot;Ptr&quot;, hwnd, &quot;UInt&quot;, uMsg, &quot;Ptr&quot;, wParam, &quot;Ptr&quot;, lParam)
}</pre>
</div>

</body>
</html>